home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Source Code / C / Applications / Macintosh Tracker 1.20 / source / Tracker Client Folder / Core 18⁄March⁄1994 / SFMultiGet.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-06-27  |  11.0 KB  |  451 lines  |  [TEXT/KAHL]

  1. /* SFMultiGet.c */
  2.  
  3. #include <StandardFile.h>
  4. #include <Resources.h>
  5. #include <Memory.h>
  6. #include <Lists.h>
  7. #include <Packages.h>
  8. #include <Files.h>
  9. #include <Controls.h>
  10. #include "SFMultiGet.h" /* Mine */
  11. #include "CSack.h" /* Mine */
  12.  
  13. /*
  14.     Hi there!
  15.     
  16.     After craving a multi-get dialog box for a while, I finally got the time
  17.     to write one. And since I could never find one on-line, I'm uploading it
  18.     far and wide (or at least to cis/aol/sumex). It works, and _should_ work
  19.     under MPW & Think. The methods are a little ugly (stringtonum), but hey,
  20.     you can write your own if you want.
  21.     
  22.     Potential improvements:
  23.         • Filtering out the files already in the list. This doesn't really
  24.           bother me, but if you want, the fileFilter function is ready.
  25.         • Better System 6 behavior. Actually, I'm not sure what the thing
  26.           looks like under 6. Probably the auto-centering is off, the
  27.           button isn't hilited, & the enter keys don't work.
  28.     
  29.     If you use this, feel free to send me a copy of the program ;)
  30.     
  31.     Manuel Veloso
  32.     9 High Rock Way #3
  33.     Allston, MA 02134-2414
  34.     
  35.     cis: 70365, 1426
  36.     aol: Fish26
  37.     net: veloso@husc10.harvard.edu
  38.     
  39.     History:
  40.     1.0    same as current, except without the scrollbar.
  41.     1.1    added a scrollbar.
  42. */
  43.  
  44. #define SFSaveDisk     0x214
  45. #define CurDirStore 0x398
  46.     
  47. enum
  48. {
  49.     okButton = 1,
  50.     blank2,
  51.     cancelButton,
  52.     item1,
  53.     ejectButton,
  54.     driveButton,
  55.     sfListBox,
  56.     scrollBar,
  57.     line1,
  58.     blank10,
  59.     filesBox,
  60.     removeButton,
  61.     addButton,
  62.     line,
  63.     myScrollBar,
  64.     kMyDialog = 128
  65. };
  66.  
  67. ListHandle    gTheList;            // list of files selected
  68. SFReply        gTheReply;            // the sf reply
  69. ControlHandle    gTheScrollBar;    // the scrollbar
  70.  
  71. /*
  72.     NOTE: the refCon of the control holds the # of files in the list AND the # of files
  73.     that are visible. The refCon starts out as a negative #; when a file is added, the
  74.     refCon is incremented. When refCon == 1, that means that scrolling must take place.
  75.     When a file is removed, the refCon is decremented by 1. Presumably, when all files
  76.     are removed the refCon == the original value.
  77. */
  78.  
  79. pascal void setItem(DialogPtr theDialog, short item, Handle theProc);
  80. pascal void hiliteItem(DialogPtr theDialog, short item, short hiliteValue);
  81. pascal void getBox(DialogPtr theDialog, short item, Rect *box);
  82. void addData(void);
  83. void removeCells(void);
  84. Boolean selected(void);
  85. pascal void myItem(DialogPtr theDialog, short itemNumber);
  86. pascal void initList(DialogPtr theDialog);
  87. pascal Boolean myFileFilter(CInfoPBPtr pb);
  88. pascal short myDlgHook(short item, DialogPtr theDialog);
  89. pascal Boolean myFilterProc(DialogPtr theDialog, EventRecord *event, short *itemHit);
  90. pascal void cleanup(void);
  91. void processData(void);
  92. void handleScrollBar(DialogPtr, EventRecord*);
  93. pascal void scrollProc(ControlHandle theControl, short theCode);
  94.  
  95. pascal void setItem(DialogPtr theDialog, short item, Handle theProc)
  96. {
  97.     short    itemType;
  98.     Rect    box;
  99.     Handle    theControl;
  100.     
  101.     GetDItem(theDialog, item, &itemType, &theControl, &box);
  102.     SetDItem(theDialog, item, itemType, theProc, &box);
  103. }
  104.     
  105. pascal void hiliteItem(DialogPtr theDialog, short item, short hiliteValue)
  106. {
  107.     short    itemType;
  108.     Rect    box;
  109.     Handle    theControl;
  110.     
  111.     GetDItem(theDialog, item, &itemType, &theControl, &box);
  112.     HiliteControl((ControlHandle) theControl, hiliteValue);
  113. }
  114.  
  115. pascal void getBox(DialogPtr theDialog, short item, Rect *box)
  116. {
  117.     short    itemType;
  118.     Handle    theControl;
  119.     
  120.     GetDItem(theDialog, item, &itemType, &theControl, box);
  121. }
  122.  
  123. /*
  124.     Initializes the list within the sfdialog. Sets the useritem to the
  125.     updateProc.
  126. */
  127.  
  128. pascal void initList(DialogPtr theDialog)
  129. {
  130.     Rect        rView, dataBounds;
  131.     Point        cSize = {0, 0};
  132.     short        temp;
  133.     FontInfo    fInfo;
  134.     GrafPtr        oldPort;
  135.     Boolean        good = false;
  136.  
  137.     GetPort(&oldPort);
  138.     SetPort(theDialog);
  139.     getBox(theDialog, filesBox, &rView);
  140.     SetRect(&dataBounds, 0, 0, 3, 0);
  141.     GetFontInfo(&fInfo);
  142.     cSize.h = rView.right;
  143.     cSize.v = fInfo.ascent + fInfo.descent + fInfo.leading;
  144.     gTheList = LNew(&rView, &dataBounds, cSize, 0, theDialog, true, false, false, false);
  145.     if (gTheList)
  146.     {
  147.         LDoDraw(true, gTheList);
  148.         (*gTheList)->selFlags = lNoNilHilite + lUseSense + lOnlyOne;
  149.         (*gTheList)->listFlags = lDoVAutoscroll;
  150.         LActivate(true, gTheList);
  151.         hiliteItem(theDialog, removeButton, 255);
  152.         setItem(theDialog, filesBox, (Handle) myItem);
  153.     }
  154.     hiliteItem(theDialog, myScrollBar, 255);
  155.     GetDItem(theDialog, myScrollBar, &temp, (Handle*)&gTheScrollBar, &dataBounds);
  156.     SetCRefCon(gTheScrollBar, -((rView.bottom - rView.top)/cSize.v));    // # of lines in box, negativized
  157.     SetCtlMin(gTheScrollBar, 0);
  158.     SetCtlMax(gTheScrollBar, GetCRefCon(gTheScrollBar));
  159.     SetPort(oldPort);
  160.     return;
  161. }
  162.  
  163. pascal void cleanup(void)
  164. {
  165.     if (gTheList) LDispose(gTheList);
  166. }
  167.  
  168. /*
  169.     Updates the list display, and does sundry drawing activities.
  170. */
  171.  
  172. pascal void myItem(DialogPtr theDialog, short itemNumber)
  173. {
  174.     Rect    box;
  175.     GrafPtr    oldPort;
  176.     
  177.     GetPort(&oldPort);
  178.     SetPort(theDialog);
  179.     
  180.     getBox(theDialog, filesBox, &box);
  181.     InsetRect(&box, -1, -1);
  182.     FrameRect(&box);
  183.     getBox(theDialog, line, &box);
  184.     FrameRect(&box);
  185.     LUpdate(theDialog->visRgn, gTheList);
  186.     SetPort(oldPort);
  187. }
  188.  
  189. // false displays the file, true doesn’t.
  190.  
  191. pascal Boolean myFileFilter(CInfoPBPtr pb)
  192. {
  193.     return false;
  194. }
  195.  
  196. /*
  197.     must return item #; if no number, nothing happens. I've remapped the
  198.     add button to the okButton, and vice-versa to avoid lots of exess code.
  199. */
  200.  
  201. pascal short myDlgHook(short item, DialogPtr theDialog)
  202. {
  203.     switch (item)
  204.     {
  205.         case sfHookFirstCall:
  206.             initList(theDialog);
  207.             break;
  208.         case okButton:            // maps to add!
  209.             addData();
  210.             if (GetCRefCon(gTheScrollBar)>0) hiliteItem(theDialog, myScrollBar, 0);
  211.             else hiliteItem(theDialog, myScrollBar, 255);
  212.             item = addButton;
  213.             break;
  214.         case addButton:            // maps to ok!
  215.             item = okButton;
  216.             break;
  217.         case removeButton:
  218.             removeCells();
  219.             hiliteItem(theDialog, removeButton, 255);
  220.             if (GetCRefCon(gTheScrollBar)>0) hiliteItem(theDialog, myScrollBar, 0);
  221.             else hiliteItem(theDialog, myScrollBar, 255);
  222.             break;
  223.     }
  224.     return item;
  225. }
  226.  
  227. // false->handle the event || true->ignore the event
  228.  
  229. pascal Boolean myFilterProc(DialogPtr theDialog, EventRecord *event, short *itemHit)
  230. {
  231.     if (event->what == mouseDown)
  232.     {
  233.         if (FrontWindow() == theDialog)
  234.         {
  235.             Rect    theView;
  236.             getBox(theDialog, filesBox, &theView);
  237.             GlobalToLocal(&(event->where));
  238.             if (PtInRect(event->where, &theView))
  239.             {
  240.                 LClick(event->where, event->modifiers, gTheList);
  241.             }
  242.             else
  243.             {
  244.                 getBox(theDialog, myScrollBar, &theView);
  245.                 if (PtInRect(event->where, &theView))
  246.                 {
  247.                     handleScrollBar(theDialog, event);
  248.                 }
  249.             }
  250.             LocalToGlobal(&(event->where));
  251.             hiliteItem(theDialog, removeButton, selected() ? 0 : 255);
  252.         }
  253.     }
  254.     return false;
  255. }
  256.  
  257. // are any cells selected?
  258.  
  259. Boolean selected(void)
  260. {
  261.     Cell    theCell = {0, 0};
  262.     
  263.     return LGetSelect(true, &theCell, gTheList);
  264. }
  265.  
  266. // remove active cells. Even though there should be only one, I go thru them all anyway.
  267. void removeCells(void)
  268. {
  269.     Cell    theCell = {0, 0};
  270.     
  271.     while(LGetSelect(true, &theCell, gTheList))
  272.     {
  273.         LDelRow(1, theCell.v, gTheList);
  274.         SetCRefCon(gTheScrollBar, GetCRefCon(gTheScrollBar) -1);    // subtract
  275.         SetCtlMax(gTheScrollBar, GetCRefCon(gTheScrollBar));            // set scroll limit
  276.     }
  277. }
  278.  
  279. //    ugly, but effective: the list is 3 columns wide, so I just stuff
  280. //    the other 2 colums with the parID and the vRefNum, respectively.
  281.  
  282. void addData(void)
  283. {
  284.     long    parID;
  285.     short    vRefNum;
  286.     Str32    text;
  287.     short    len;
  288.     Cell    theCell = {0, 0};
  289.     
  290.     theCell.v = (**gTheList).dataBounds.bottom+1;
  291.     theCell.v = LAddRow(1, theCell.v, gTheList);
  292.     
  293.     parID = *((long *)CurDirStore);
  294.     vRefNum = -1 * (*(short *)SFSaveDisk);
  295.  
  296.     len = gTheReply.fName[0];
  297.     LSetCell(&(gTheReply.fName[1]), len, theCell, gTheList);    // name
  298.  
  299.     NumToString(parID, text);
  300.     len = text[0];
  301.     theCell.h++;
  302.     LSetCell(&(text[1]), len, theCell, gTheList);                // parent id
  303.     
  304.     parID = vRefNum;
  305.     NumToString(parID, text);
  306.     len = text[0];
  307.     theCell.h++;
  308.     LSetCell(&(text[1]), len, theCell, gTheList);                // vrefnum
  309.     SetCRefCon(gTheScrollBar, GetCRefCon(gTheScrollBar) + 1);    // add 1 file to count
  310.     SetCtlMax(gTheScrollBar, GetCRefCon(gTheScrollBar));            // set scroll limit
  311. }
  312.  
  313. //    just a test, to make sure all the files are there.
  314.  
  315. void processData(void)
  316. {
  317.     FSSpec    theFile;
  318.     long    num;
  319.     Str32    text;
  320.     Cell    theCell = {0, 2};
  321.     short    len;
  322.     
  323.     for (theCell.v = 0; theCell.v < (**gTheList).dataBounds.bottom; theCell.v++)
  324.     {
  325.         len = 63;
  326.         LGetCell((theFile.name)+1, &len, theCell, gTheList);
  327.         theFile.name[0] = len;
  328.         StringToNum(theFile.name, &(theFile.parID));
  329.         theFile.vRefNum = theFile.parID;
  330.         
  331.         theCell.h--;
  332.         len = 63;
  333.         LGetCell((theFile.name)+1, &len, theCell, gTheList);
  334.         theFile.name[0] = len;
  335.         StringToNum(theFile.name, &(theFile.parID));
  336.         
  337.         theCell.h--;
  338.         len = 63;
  339.         LGetCell(theFile.name+1, &len, theCell, gTheList);
  340.         theFile.name[0] = len;
  341.         theCell.h = 2;
  342.     }
  343. }
  344.  
  345. /* this routine has been left in here for purposes of testing and completeness */
  346. //void main(void)
  347. //{
  348. //    Point    where = {-1, -1};
  349. //        
  350. //    // note: the file filter can be omitted, if you want.
  351. //    SFPGetFile(where, "\pSelect files:", myFileFilter, -1, nil, myDlgHook, &gTheReply, kMyDialog, myFilterProc);
  352. //
  353. //    if (gTheReply.good)
  354. //    {
  355. //        processData();
  356. //    }
  357. //    cleanup();
  358. //}
  359.  
  360. void handleScrollBar(DialogPtr theDialog, EventRecord *event)
  361. {
  362.     short            thePart, oldVal;
  363.     Point            pt = (*event).where;
  364.     ControlHandle    theControl;
  365.     
  366.     if ((thePart = FindControl(pt, theDialog, &theControl)) == inThumb)
  367.     {
  368.         oldVal = GetCtlValue(theControl);
  369.         thePart = TrackControl(theControl, pt, nil);
  370.         LScroll(0, GetCtlValue(theControl) - oldVal, gTheList);
  371.     }
  372.     else
  373.     {
  374.         thePart = TrackControl(theControl, pt, &scrollProc);
  375.     }
  376. }
  377.  
  378. pascal void scrollProc(ControlHandle theControl, short theCode)
  379. {
  380.     short    theValue = GetCtlValue(theControl);
  381.     switch (theCode)
  382.     {
  383.         case inPageDown:
  384.         case inDownButton:
  385.             theValue++;
  386.             LScroll(0, 1, gTheList);
  387.             break;
  388.         case inPageUp:
  389.         case inUpButton:
  390.             LScroll(0, -1, gTheList);
  391.             theValue--;
  392.             break;
  393.     }
  394.     SetCtlValue(theControl, theValue);
  395. }
  396.  
  397.  
  398. /*********************************************************************************/
  399.  
  400.  
  401. /* returns a sack containing FSSpecs if good, otherwise returns NIL if cancelled */
  402. CSack*        SFMultiGet(void)
  403.     {
  404.         Point            where = {-1, -1};
  405.         CSack*        FileList;
  406.  
  407.         /* note: the file filter can be omitted, if you want. */
  408.         SFPGetFile(where, "\pSelect files:", (void*)myFileFilter, -1, nil, myDlgHook, &gTheReply, kMyDialog, myFilterProc);
  409.  
  410.         if (gTheReply.good)
  411.             {
  412.                 FSSpec    theFile;
  413.                 long        num;
  414.                 Str32        text;
  415.                 Cell        theCell = {0, 2};
  416.                 short        len;
  417.  
  418.                 FileList = new CSack;
  419.                 FileList->ISack(sizeof(FSSpec),sizeof(FSSpec) * 16);
  420.  
  421.                 for (theCell.v = 0; theCell.v < (**gTheList).dataBounds.bottom; theCell.v++)
  422.                 {
  423.                     len = 63;
  424.                     LGetCell((theFile.name)+1, &len, theCell, gTheList);
  425.                     theFile.name[0] = len;
  426.                     StringToNum(theFile.name, &(theFile.parID));
  427.                     theFile.vRefNum = theFile.parID;
  428.                     
  429.                     theCell.h--;
  430.                     len = 63;
  431.                     LGetCell((theFile.name)+1, &len, theCell, gTheList);
  432.                     theFile.name[0] = len;
  433.                     StringToNum(theFile.name, &(theFile.parID));
  434.                     
  435.                     theCell.h--;
  436.                     len = 63;
  437.                     LGetCell(theFile.name+1, &len, theCell, gTheList);
  438.                     theFile.name[0] = len;
  439.                     theCell.h = 2;
  440.  
  441.                     FileList->PushElement(&theFile);
  442.                 }
  443.             }
  444.          else
  445.             {
  446.                 FileList = NIL;
  447.             }
  448.         cleanup();
  449.         return FileList;
  450.     }
  451.